package bb.lanxing.lib.devices.sprint;

import android.Manifest;
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;
//import com.igexin.push.config.c;
//import bb.lanxing.device.sgdevcie.utils.BleManagerDFUUtilsKt;
import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;

import com.bes.bessdk.BesSdkConstants;
import com.bes.bessdk.scan.BtHeleper;
import com.bes.bessdk.utils.SPHelper;
import com.clj.fastble.BleManager;

import bb.lanxing.App;
import bb.lanxing.lib.devices.api.SmartDevice;
//import bb.lanxing.lib.devices.ble.ble.base.BaseResponsiveCharacteristicKt;
import bb.lanxing.lib.devices.core.ble.AbsBleDevice;
import bb.lanxing.lib.devices.core.ble.BaseBluetoothGattCallback;
import bb.lanxing.lib.devices.core.ble.SpecificationAttributes;
import bb.lanxing.lib.devices.core.dfu.IDfuAdapter;
import bb.lanxing.lib.devices.core.dfu.IDfuDevice;
import bb.lanxing.lib.devices.core.exception.AbortedException;
import bb.lanxing.lib.devices.core.exception.InvalidDataException;
import bb.lanxing.lib.devices.core.exception.TimeoutException;
import bb.lanxing.lib.devices.core.utils.CharacteristicValueHelper;
import bb.lanxing.lib.devices.sprint.utils.SprintFileHelper;
import bb.lanxing.lib.devices.sprint.utils.SprintSyncLogFileUtils;
import bb.lanxing.lib.devices.sprint.ymodem.FileYmodemInputStream;
import bb.lanxing.lib.devices.sprint.ymodem.YModem;
import bb.lanxing.lib.devices.sprint.ymodem.YModemInputStream;
import bb.lanxing.lib.devices.sprint.ymodem.YModems;
import bb.lanxing.lib.devices.sprint.ymodem.YModenOutputStream;
import bb.lanxing.lib.devices.utils.ByteUtils;
import bb.lanxing.lib.devices.utils.DeviceCompat;
import bb.lanxing.model.database.Workout;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Locale;
import java.util.UUID;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit;

import static android.bluetooth.BluetoothDevice.TRANSPORT_LE;
import static com.bes.bessdk.scan.BtHeleper.getBluetoothAdapter;
import static com.bes.sdk.utils.DeviceProtocol.PROTOCOL_GATT_BR_EDR;

//@SuppressLint("MissingPermission")
public class XossDevice extends AbsBleDevice implements XossDeviceController, IDfuDevice {
    final private static String TAG = "XossDevice";
    private static final String EMPTY_NAME = "";
    private static final String FILE_LIST_NAME = "filelist.txt";
    private static final String NONE = "0x00";
    private static final int OP_GET_FILE = 1;
    private static final int OP_SEND_FILE = 2;
    private static final int OP_TIMEOUT = 5;
    private static final int OP_DELETE_FILE = 6;
    private static final int OP_SEND_COMMAND = 7;
    private static final int OP_DELETE_ALL_FILE = 8;
    private static final String SETTINGS_FILE_NAME = "Setting.json";
    private final int MAX_RETRY_COUNT;
    private boolean isInit;
    private long lastTransmissionTime;
    private volatile boolean mAborted;
    private BluetoothGattCharacteristic mControlPoint;
    private IDfuAdapter mDfuAdapter;
    private IDeviceLogger mLogger;
    private SprintNotifier mNotifier;
    private BluetoothGattCharacteristic mPacketReceiver;
    private BluetoothGattCharacteristic mPacketSender;
    private final BlockingDeque<Response> mSprintControlPointQueue;
    private final BlockingDeque<Byte> mSprintTransmissionControlQueue;
    private String rootDir;
    SimpleDateFormat simpleDateFormat;
    MtuRequestCallback tempMtuRequestCallback;
    private YModenOutputStream yModenOutputStream;
    private static final UUID WINGS_SERVICE_UUID = UUID.fromString("6E400001-B5A3-F393-E0A9-E50E24DCCA9E");
    private static final UUID WINGS_CONTROL_POINT = UUID.fromString("6E400004-B5A3-F393-E0A9-E50E24DCCA9E");
    private static final UUID WINGS_YMODEM_PACKAGE_RECEIVER = UUID.fromString("6E400002-B5A3-F393-E0A9-E50E24DCCA9E");
    private static final UUID WINGS_YMODEM_PACKAGE_SENDER = UUID.fromString("6E400003-B5A3-F393-E0A9-E50E24DCCA9E");
    //test code
    public static Context testContext;
    public static BluetoothAdapter adapter = null;
    protected boolean _checkDeviceStatusAfterSend() {
        return false;
    }

    protected boolean isSendDynamicSizeYModems(File file) {
        return false;
    }

    public XossDevice(Context context, SmartDevice smartDevice) {
        this(context, smartDevice, null);
    }

    public XossDevice(Context context, SmartDevice smartDevice, String str) {
        super(smartDevice);
        this.MAX_RETRY_COUNT = 5;
        this.mSprintControlPointQueue = new LinkedBlockingDeque();
        this.mSprintTransmissionControlQueue = new LinkedBlockingDeque();
        this.lastTransmissionTime = 0L;
        this.isInit = false;
        this.tempMtuRequestCallback = null;
        this.mLogger = null;
        this.simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        this.rootDir = str;
        init(context, smartDevice.getAddress(), new SprintCallback(this));
        //test code
        adapter = getBluetoothAdapter(context);
    }


    @Override
    public void init(Context context, String str, BluetoothGattCallback bluetoothGattCallback) {
        super.init(context, str, bluetoothGattCallback);
        testContext = context;
        this.mNotifier = new LocalSprintNotifier();
    }

    @Override
    protected void initBeforeConnect() {
        this.tempMtuRequestCallback = null;
    }


    @Override
    public void onServicesDiscovered() {
        super.onServicesDiscovered();
        IDfuAdapter iDfuAdapter = this.mDfuAdapter;
        if (iDfuAdapter != null) {
            iDfuAdapter.release();
            this.mDfuAdapter = null;
        }
        BluetoothGattService service = this.mBluetoothGatt.getService(WINGS_SERVICE_UUID);
        if (service == null) {
            _close();
        }
        BluetoothGattCharacteristic characteristic = service.getCharacteristic(WINGS_CONTROL_POINT);
        BluetoothGattCharacteristic characteristic2 = service.getCharacteristic(WINGS_YMODEM_PACKAGE_RECEIVER);
        BluetoothGattCharacteristic characteristic3 = service.getCharacteristic(WINGS_YMODEM_PACKAGE_SENDER);
        if (characteristic == null || characteristic2 == null || characteristic3 == null) {
            _close();
            return;
        }
        this.mControlPoint = characteristic;
        this.mPacketReceiver = characteristic2;
        this.mPacketSender = characteristic3;
        setCharacteristicNotification(characteristic, true);
        setCharacteristicNotification(characteristic3, true);
        Log.d("wangsm_bt", " XossDevice, onServicesDiscovered, this.rootDir:  " + this.rootDir);
        SprintFileHelper.clearFiles(this.rootDir);

        //add by bb for model,sn is null
        readModel();
        readSerial();
    }

    public SprintNotifier getNotifier() {
        return this.mNotifier;
    }

    public void post(Runnable runnable) {
        Handler handler = getHandler();
        if (handler != null) {
            handler.post(runnable);
        }
    }

    @Override
    public void close() {
        abort();
        super.close();
    }

    @Override
    public boolean isInit() {
        return this.isInit;
    }

    @Override
    public void setIsInit(boolean z) {
        this.isInit = z;
    }

    @Override
    public void requestMtu(int i, MtuRequestCallback mtuRequestCallback) {
/*        if (ActivityCompat.checkSelfPermission(App.getContext(), Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
            // TODO: Consider calling
            //    ActivityCompat#requestPermissions
            // here to request the missing permissions, and then overriding
            //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
            //                                          int[] grantResults)
            // to handle the case where the user grants the permission. See the documentation
            // for ActivityCompat#requestPermissions for more details.
            Log.d("wangsm_bt","XossDevice requestMtu,bluetooth permission required! ");
            Log.e(TAG, "requestMtu: bluetooth permission required!");
            return;
        }*/
        if (this.mBluetoothGatt == null || !isConnected() || !this.mBluetoothGatt.requestMtu(i)) {
            Log.d("wangsm_bt","XossDevice wangsm,requestMtu to onMtuResult ");
            mtuRequestCallback.onMtuResult(false, this.mtuExchanged);
            return;
        }
        Log.d("wangsm_bt","XossDevice wangsm,requestMtu to sendEmptyMessageDelayed OP_REQUEST_MTU_TIMEOUT");
        this.tempMtuRequestCallback = mtuRequestCallback;
        this.mLocalHandler.sendEmptyMessageDelayed(OP_REQUEST_MTU_TIMEOUT, 1500L/*c.j*/);
    }

    @Override
    public void e(String str) {
        IDeviceLogger iDeviceLogger = this.mLogger;
        if (iDeviceLogger != null) {
            iDeviceLogger.log(getTag(), str);
        }
    }

    @Override
    public void d(String str) {
        IDeviceLogger iDeviceLogger = this.mLogger;
        if (iDeviceLogger != null) {
            iDeviceLogger.log(getTag(), str);
        }
    }

    @Override
    public void setLogger(IDeviceLogger iDeviceLogger) {
        this.mLogger = iDeviceLogger;
    }

    @Override
    public void handleMtuRequest(int i, int i2) {
        this.mLocalHandler.removeMessages(OP_REQUEST_MTU_TIMEOUT);
        if (i == 0) {
            if (this.tempMtuRequestCallback == null) {
                return;
            }
            this.mtuExchanged = i2;
            this.tempMtuRequestCallback.onMtuResult(true, this.mtuExchanged);
            this.tempMtuRequestCallback = null;
            return;
        }
        MtuRequestCallback mtuRequestCallback = this.tempMtuRequestCallback;
        if (mtuRequestCallback != null) {
            mtuRequestCallback.onMtuResult(false, this.mtuExchanged);
            this.tempMtuRequestCallback = null;
        }
    }

    @Override
    public void delete(String str) {
        if (TextUtils.isEmpty(str) || !isServicesDiscovered()) {
            return;
        }
        Handler handler = getHandler();
        if (Looper.myLooper() == handler.getLooper()) {
            _delete(str);
        } else {
            handler.obtainMessage(OP_DELETE_FILE, str).sendToTarget();
        }
    }


    public void _delete(String str) {
        Command create = Commands.create(Commands.DEL_SINGLE_FILE, ByteUtils.stringToBytes(str));
        try {
            Response execute = execute(create);
            if (execute.getStatus() != Commands.FILE_NOT_FOUNT && execute.getStatus() != Commands.DEL_FILE_ON_SUCCESSFUL) {
                this.mNotifier.notifyCmdStatus(create, 1, null);
            }
            this.mNotifier.notifyCmdStatus(create, 0, null);
        } catch (TimeoutException e) {
            this.mNotifier.notifyCmdStatus(create, 1, null);
            e(e);
        }
    }

    @Override
    public void deleteAll() {
        if (isServicesDiscovered()) {
            Handler handler = getHandler();
            if (Looper.myLooper() == handler.getLooper()) {
                _deleteAll();
            } else {
                handler.obtainMessage(OP_DELETE_ALL_FILE, "").sendToTarget();
            }
        }
    }

    protected void _deleteAll() {
        Command create = Commands.create(Commands.DEL_MULTIP_FILES, ByteUtils.stringToBytes(NONE));
        try {
            Response execute = execute(create);
            if (execute.getStatus() != Commands.FILE_NOT_FOUNT && execute.getStatus() != Commands.DEL_FILE_ON_SUCCESSFUL) {
                this.mNotifier.notifyCmdStatus(create, 1, null);
            }
            this.mNotifier.notifyCmdStatus(create, 0, null);
        } catch (TimeoutException e) {
            this.mNotifier.notifyCmdStatus(create, 1, null);
            e(e);
        }
    }

    @Override
    public void reset() {
        delete(SETTINGS_FILE_NAME);
    }

    @Override
    public Response getResponse() throws TimeoutException {
        return getControlPointResponse();
    }

    @Override
    public boolean isDisRead() {
        return getSerial() != null && !getSerial().isEmpty() && getHardwareVersion() != null && !getHardwareVersion().isEmpty() && getFirmwareVersion() != null && !getFirmwareVersion().isEmpty() && getManufacturer() != null && !getManufacturer().isEmpty() && getModel() != null && !getModel().isEmpty();
    }

    @Override
    public boolean isRegistryInfoRead() {
        return getSerial() != null && !getSerial().isEmpty() && getFirmwareVersion() != null && !getFirmwareVersion().isEmpty() && getManufacturer() != null && !getManufacturer().isEmpty() && getModel() != null && !getModel().isEmpty();
    }

    @Override
    public long getLastTransmissionTime() {
        return this.lastTransmissionTime;
    }

    public void getFileList() {
        getFile(FILE_LIST_NAME);
    }

    @Override
    public void getFile(String str) {
        Log.d("wangsm_bt", " XossDevice,str: " + str);
        Log.d("wangsm_bt", " XossDevice,!isServicesDiscovered(): " + !isServicesDiscovered());
        if (TextUtils.isEmpty(str) || !isServicesDiscovered()) {
            Log.d("wangsm_bt", " XossDevice,getFile do nothing ,return");
            return;
        }
        Handler handler = getHandler();
        if (Looper.myLooper() == handler.getLooper()) {
            Log.d("wangsm_bt", " XossDevice,_getFile begin");
            _getFile(str);
        } else {
            Log.d("wangsm_bt", " XossDevice,getFile,send msg to target , str: " + str);
            handler.obtainMessage(OP_GET_FILE, str).sendToTarget();
        }
    }

    @Override
    public void sendFile(String str) {
        if (TextUtils.isEmpty(str)) {
            return;
        }
        File file = new File(str);
        if (!file.exists()) {
            this.mNotifier.notifyCmdStatus(Commands.create(Commands.POST_FILE, file.getName().getBytes()), -5, null);
        } else if (!isServicesDiscovered()) {
            this.mNotifier.notifyCmdStatus(Commands.create(Commands.POST_FILE, file.getName().getBytes()), -1, null);
        } else {
            Handler handler = getHandler();
            if (Looper.myLooper() == handler.getLooper()) {
                _sendFile(file);
            } else {
                handler.obtainMessage(OP_SEND_FILE, file).sendToTarget();
            }
        }
    }

    @Override
    public void registerXossDeviceListener(SprintListener sprintListener) {
        SprintNotifier sprintNotifier = this.mNotifier;
        if (sprintNotifier instanceof LocalSprintNotifier) {
            ((LocalSprintNotifier) sprintNotifier).registerSprintListener(sprintListener);
        }
    }

    @Override
    public void unregisterXossDeviceListener(SprintListener sprintListener) {
        SprintNotifier sprintNotifier = this.mNotifier;
        if (sprintNotifier instanceof LocalSprintNotifier) {
            ((LocalSprintNotifier) sprintNotifier).unregisterSprintListener(sprintListener);
        }
    }

    @Override
    public boolean sendCmd(Command command) {
        d("Send cmd: " + command.toString());
        if (execute(AbsBleDevice.Request.newWriteRequest(this.mControlPoint, Commands.toBytes(command)))) {
            Log.d("wangsm_bt", " sendCmd ok, write controlpoint cmd" + command.toString());
            return true;
        }
        e("Failed to send cmd.");
        this.mNotifier.notifyCmdStatus(command, 1, null);//LocalSprintNotifier.java
        return false;
    }

    @Override
    public Response execute(Command command) throws TimeoutException {
        clearControlPointQueue();
        sendCmd(command);
        return getControlPointResponse();
    }

    @Override
    public Response execute(Command command, long j) throws TimeoutException {
        clearControlPointQueue();
        sendCmd(command);
        return getControlPointResponse(j);
    }

    @Override
    public boolean sendCmdAsync(Command command) {
        if (isServicesDiscovered()) {
            Handler handler = getHandler();
            if (Looper.myLooper() == handler.getLooper()) {
                sendCmd(command);
                return true;
            }
            handler.obtainMessage(OP_SEND_COMMAND, command).sendToTarget();
            return true;
        }
        return false;
    }

    protected byte getTransmissionControlCmd() throws TimeoutException {
        return getTransmissionControlCmd(5000);
    }

    protected byte getTransmissionControlCmd(int i) throws TimeoutException {
        try {
            Byte pollLast = this.mSprintTransmissionControlQueue.pollLast(i, TimeUnit.MILLISECONDS);
            if (pollLast == null) {
                throw new TimeoutException("No transmission control cmd in queue.");
            }
            return pollLast.byteValue();
        } catch (InterruptedException e) {
            throw new TimeoutException(e);
        }
    }

    protected Response getControlPointResponse(long j) throws TimeoutException {
        try {
            Response pollLast = this.mSprintControlPointQueue.pollLast(j, TimeUnit.MILLISECONDS);
            if (pollLast != null) {
                return pollLast;
            }
            throw new TimeoutException("No response in queue.");
        } catch (InterruptedException e) {
            throw new TimeoutException(e);
        }
    }

    protected Response getControlPointResponse() throws TimeoutException {
        return getControlPointResponse(15000L/*BaseResponsiveCharacteristicKt.RESPONSE_TIME_OUT*/);
    }

    private void resetValuesForTransmission() {
        this.mAborted = false;
        clearControlPointQueue();
        clearTransmissionControlQueue();
    }


    public void _getFile(String str) {
        Log.d("wangsm_bt","_getFile, begin: ");
        Command create = Commands.create(Commands.GET_FILE, ByteUtils.stringToBytes(str));
        Log.d("wangsm_bt","_getFile, str: " + str);

        try {
            try {
                refreshDeviceState(Workout.STATUS_PAUSED, str);
                resetValuesForTransmission();
            } catch (Exception e) {
                handleExceptionForReceiver(create, e);
                refreshDeviceState(Workout.STATUS_WORKING, EMPTY_NAME);
                YModenOutputStream yModenOutputStream = this.yModenOutputStream;
                if (yModenOutputStream == null) {
                    return;
                }
                try {
                    yModenOutputStream.close();
                } catch (IOException e2) {
//                    e = e2;
                    e(e2);
                    this.yModenOutputStream.reset();
                    this.yModenOutputStream = null;
                }
            }
            if (!sendCmd(create)) {
                refreshDeviceState(Workout.STATUS_WORKING, EMPTY_NAME);
                YModenOutputStream yModenOutputStream2 = this.yModenOutputStream;
                if (yModenOutputStream2 != null) {
                    try {
                        yModenOutputStream2.close();
                    } catch (IOException e3) {
                        e(e3);
                    }
                    this.yModenOutputStream.reset();
                    this.yModenOutputStream = null;
                    return;
                }
                return;
            }
            Response controlPointResponse = getControlPointResponse();
            if (controlPointResponse.getStatus() == 4) {
                controlPointResponse = getControlPointResponse();
            }
            if (controlPointResponse.getStatus() != 6) {
                throw new IllegalStateException("Can't get file, device status not correct.");
            }

            Log.d("wangsm_bt"," XossDevice, _getFile,the rootDir: " + this.rootDir);
            this.yModenOutputStream = new YModenOutputStream(this.rootDir);
            sendYModemCmdSync(YModems.ST_C);
            receivePackageByOne(create, MAX_RETRY_COUNT);
            d(String.format(Locale.getDefault(), "fileName: %s, length: %d", this.yModenOutputStream.getFileName(), this.yModenOutputStream.getTotalBytes()));
            sendYModemCmdSync(YModems.ST_C);
            receivePackages(create);
            Log.d("wangsm_bt", " XossDevice _getFile receivePackages end ");
            this.lastTransmissionTime = System.currentTimeMillis();
            refreshDeviceState(Workout.STATUS_WORKING, EMPTY_NAME);
            Log.d("wangsm_bt", " XossDevice _getFile refreshDeviceState end ");
            YModenOutputStream yModenOutputStream3 = this.yModenOutputStream;
            if (yModenOutputStream3 != null) {
                try {
                    yModenOutputStream3.close();
                } catch (IOException e4) {
//                    e = e4;
                    e(e4);
                    this.yModenOutputStream.reset();
                    this.yModenOutputStream = null;
                }
                this.yModenOutputStream.reset();
                this.yModenOutputStream = null;
            }
        } catch (Throwable th) {
            refreshDeviceState(Workout.STATUS_WORKING, EMPTY_NAME);
            YModenOutputStream yModenOutputStream4 = this.yModenOutputStream;
            if (yModenOutputStream4 != null) {
                try {
                    yModenOutputStream4.close();
                } catch (IOException e5) {
                    Log.d("wangsm_bt"," the e5 exception " + e5.getMessage());
                    e(e5);
                }
                this.yModenOutputStream.reset();
                this.yModenOutputStream = null;
                th.printStackTrace();//add by bb test code
            }
//            throw th;
        }
    }

    private void _sendData(byte[] bArr, int i) throws TimeoutException, AbortedException, IllegalStateException {
        if (!isServicesDiscovered()) {
            throw new IllegalStateException("Connection lost");
        }
        int i2 = this.mtuExchanged - 3;
        int length = bArr.length;
        int i3 = 0;
        while (i3 < length) {
            if (this.mAborted) {
                throw new AbortedException("Abort by user.");
            }
            int min = Math.min(i2, length - i3);
            byte[] bArr2 = new byte[min];
            System.arraycopy(bArr, i3, bArr2, 0, min);
            execute(AbsBleDevice.Request.newWriteRequest(this.mPacketReceiver, bArr2));
            i3 += min;
            d("Send data: " + ByteUtils.printlnByteArrayToUnsignHexString(bArr2));
        }
        d("Waiting for ack");
        byte transmissionControlCmd = getTransmissionControlCmd();
        if (transmissionControlCmd != 21) {
            if (transmissionControlCmd == 24) {
                throw new IllegalStateException("Abort by sprint.");
            }
        } else if (i > 0) {
            e("Send package again");
            _sendData(bArr, i - 1);
        } else {
            throw new TimeoutException("Remote device is not response.");
        }
    }

    private boolean _sendData(Command command, YModemInputStream yModemInputStream) throws AbortedException, TimeoutException, IllegalStateException, IOException {
        _sendData(YModems.toBytes(yModemInputStream.getFirstPacket()), MAX_RETRY_COUNT);
        getTransmissionControlCmd();
        long totalSize = yModemInputStream.getTotalSize();
        long j = 0;
        while (true) {
            byte[] readPacketRaw = yModemInputStream.readPacketRaw();
            if (readPacketRaw == null) {
                break;
            }
            _sendData(readPacketRaw, MAX_RETRY_COUNT);
            j += readPacketRaw.length;
            float min = Math.min(100.0f, (((float) j) / ((float) totalSize)) * 100.0f);
            this.mNotifier.notifyProgressUpdate(command, min);
            d(String.format("Send data: total(%d), sent(%d),percent(%f)", totalSize, j, min));
        }
        sendYModemCmdSync((byte) 4);
        byte transmissionControlCmd = getTransmissionControlCmd();
        if (transmissionControlCmd != 21) {
            d("Expected a NAK, but received a " + Integer.toHexString(transmissionControlCmd));
            return false;
        }
        sendYModemCmdSync((byte) 4);
        byte transmissionControlCmd2 = getTransmissionControlCmd();
        if (transmissionControlCmd2 == 6) {
            d("Send file on success: " + yModemInputStream.getFileName());
        } else {
            d("Send file on failed: " + yModemInputStream.getFileName());
        }
        return transmissionControlCmd2 == 6;
    }


    public void _sendFile(File file) {
        Response controlPointResponse;
        String name = file.getName();
        refreshDeviceState(Workout.STATUS_PAUSED, name);
        Command create = Commands.create(Commands.POST_FILE, ByteUtils.stringToBytes(name));
        resetValuesForTransmission();
        try {
            sendCmd(create);
            controlPointResponse = getControlPointResponse();
            if (controlPointResponse.getStatus() == 4) {
                controlPointResponse = getControlPointResponse();
            }
            if (controlPointResponse.getStatus() != 8) {
                throw new IllegalStateException("Device status not correct.");
            }
            getTransmissionControlCmd();
            FileYmodemInputStream fileYmodemInputStream = new FileYmodemInputStream(file);
            if (isSendDynamicSizeYModems(file)) {
                fileYmodemInputStream.setUseBigDataSize(true);
            }
            boolean _sendData = _sendData(create, fileYmodemInputStream);
            if (_checkDeviceStatusAfterSend() && getControlPointResponse().getStatus() != 4) {
                throw new IllegalStateException("Device status not correct.");
            }
            this.mNotifier.notifyCmdStatus(create, _sendData ? 0 : 1, create.toBytes());
        } catch (Exception e) {
            handleExceptionForSender(create, e);
        }
        this.lastTransmissionTime = System.currentTimeMillis();
        refreshDeviceState(Workout.STATUS_WORKING, EMPTY_NAME);
    }

    private YModem receivePackageByOne(Command command, int i) throws TimeoutException, AbortedException {
        if (this.mAborted) {
            SprintSyncLogFileUtils.saveSyncELog("AbortedException : aborted by user");
            throw new AbortedException("Abort by user!!");
        }
        try {
            YModem readPacket = this.yModenOutputStream.readPacket();
            Log.d("wangsm_bt", " XossDevice receivePackageByOne");
            float f = 0.0f;
            if (this.yModenOutputStream.getTotalBytes() > 0) {
                f = (((float) this.yModenOutputStream.getBytesReceived()) / ((float) this.yModenOutputStream.getTotalBytes())) * 100.0f;
            }
            d(String.format("Received: %d, Total: %d, Percent: %f", yModenOutputStream.getBytesReceived(), yModenOutputStream.getTotalBytes(), f));
            this.mNotifier.notifyProgressUpdate(command, f);
            this.yModenOutputStream.reset();
            sendYModemCmdSync((byte) 6);
            return readPacket;
        } catch (Exception e) {
            if (!isServicesDiscovered()) {
                SprintSyncLogFileUtils.saveSyncELog("AbortedException:Connection has been  lost.");
                throw new AbortedException("Connection has been      lost.");
            }
            if (e instanceof InvalidDataException) {
                SprintSyncLogFileUtils.saveSyncELog("InvalidDataException : Sprint :L590");
            } else if (e instanceof TimeoutException) {
                SprintSyncLogFileUtils.saveSyncELog("TimeoutException : readPacket() wait over 5000 ms ");
            }
            if (this.mAborted) {
                SprintSyncLogFileUtils.saveSyncELog("AbortedException : aborted by user");
                throw new AbortedException("Abort by user!!");
            }
            SprintSyncLogFileUtils.saveSyncELog("now already received" + this.yModenOutputStream.getBytesReceived());
            e(e);
            if (i > 0) {
                Log.e("ReadPack", "too much exception");
                this.yModenOutputStream.reset();
                sendYModemCmdSync((byte) 21);
                return receivePackageByOne(command, i - 1);
            }
            SprintSyncLogFileUtils.saveSyncELog("AbortedException : retryCount == 0 ,retry over times");
            throw new AbortedException("Unknown error");
        }
    }

    private void receivePackages(Command command) throws AbortedException, TimeoutException {
        int count = 0;//test code
        do {
            count++;
            Log.d("wangsm_bt", " XossDevice receivePackages,count: " + count);
            receivePackageByOne(command, MAX_RETRY_COUNT);
        } while (this.yModenOutputStream.getBytesReceived() < this.yModenOutputStream.getTotalBytes());
        getTransmissionControlCmd();
        sendYModemCmdSync((byte) 21);
        if (getTransmissionControlCmd() == 4) {
            sendYModemCmdSync((byte) 6);
            String fileName = this.yModenOutputStream.getFileName();
            Log.d("wangsm_bt", " XossDevice receivePackages, fileName: " + fileName);
            d("Got a file: " + fileName);//origin code test
            File transferReceivedFileByName = transferReceivedFileByName(fileName);
            Log.d("wangsm_bt", " XossDevice receivePackages, finish transfer file name: ");
            if (transferReceivedFileByName != null) {
                Log.d("wangsm_bt", " XossDevice receivePackages, transferTo : " + fileName);
                this.yModenOutputStream.transferTo(transferReceivedFileByName.getAbsolutePath());
                this.mNotifier.notifyFileReceived(transferReceivedFileByName.getAbsolutePath());
                this.mNotifier.notifyCmdStatus(command, 0, command.toBytes());
                return;
            }//test
            {
                Log.d("wangsm_bt", " XossDevice receivePackages, transferReceivedFileByName is null: ");
            }
            Log.d("wangsm_bt", " XossDevice receivePackages, (getTransmissionControlCmd() == 4 ,return ");
            this.mNotifier.notifyCmdStatus(command, 1, command.toBytes());
            return;
        }
        Log.d("wangsm_bt", " XossDevice receivePackages, end return ");
        this.mNotifier.notifyCmdStatus(command, 1, command.toBytes());
    }

    protected File transferReceivedFileByName(String str) {
        Log.d("wangsm_bt", " XossDevice transferReceivedFileByName, return new file , ");
        return new File(this.rootDir, str);
    }


    public void handleExceptionForSender(Command command, Throwable th) {
        if (th instanceof TimeoutException) {
            this.mNotifier.notifyCmdStatus(command, -3, null);
        } else if (th instanceof AbortedException) {
            this.mNotifier.notifyCmdStatus(command, -2, null);
        } else if (th instanceof IllegalStateException) {
            this.mNotifier.notifyCmdStatus(command, -4, null);
        }
        e(th);
    }

    protected void handleExceptionForReceiver(Command command, Throwable th) {
        byte[] bytes = command.toBytes();
        if (th instanceof TimeoutException) {
            this.mNotifier.notifyCmdStatus(command, -3, bytes);
        } else if (th instanceof AbortedException) {
            if (isServicesDiscovered()) {
                sendCmd(Commands.create(Commands.ABORT_TREANSFER, null));
            }
            this.mNotifier.notifyCmdStatus(command, -2, bytes);
        } else if (th instanceof IllegalStateException) {
            this.mNotifier.notifyCmdStatus(command, -4, bytes);
        } else {
            this.mNotifier.notifyCmdStatus(command, 1, bytes);
        }
        e(th);
    }

    @Override
    public IDfuAdapter getDfuAdapter() {
        if (this.mDfuAdapter == null) {
            this.mDfuAdapter = new SprintDfuAdapter(this.mAppContext, this);
        }
        return this.mDfuAdapter;
    }

    @Override
    protected boolean shouldRefreshCache() {
        return this.mDfuAdapter != null;
    }

    @Override
    public boolean shouldAutoConnection() {
        return this.mDfuAdapter != null;
    }

    @Override
    public void abort() {
        this.mAborted = true;
    }

    protected void clearControlPointQueue() {
        this.mSprintControlPointQueue.clear();
    }

    protected void clearTransmissionControlQueue() {
        this.mSprintTransmissionControlQueue.clear();
    }

    private void sendYModemCmdSync(byte b) {
        if (isServicesDiscovered()) {
            d("Send ymodem cmd: " + Integer.toHexString(b));
            execute(AbsBleDevice.Request.newWriteRequest(this.mPacketReceiver, new byte[]{b}));
        }
    }

    public void ensureIdleStatus() {
        try {
            Command create = Commands.create(Commands.STOP, null);
            Response execute = execute(create);
            this.mNotifier.notifyCmdStatus(create, execute.getStatus(), null);
            if (execute.getStatus() == 4) {
                return;
            }
            sendCmd(Commands.create(Commands.IDLE, null));
        } catch (TimeoutException e) {
            e(e);
            sendCmd(Commands.create(Commands.IDLE, null));
        }
    }


    @Override
    public void handleMessage(Message message) {
        super.handleMessage(message);
        int i = message.what;
        if (i == OP_GET_FILE) {
            Log.d("wangsm_bt", " handleMessage, to getfile");
            _getFile((String) message.obj);
        } else if (i == OP_SEND_FILE) {
            _sendFile((File) message.obj);
        } else if (i == OP_DELETE_FILE) {
            _delete((String) message.obj);
        } else if (i == OP_SEND_COMMAND) {
            sendCmd((Command) message.obj);
        } else if (i == OP_DELETE_ALL_FILE) {
            _deleteAll();
        }
    }

    public static class SprintCallback extends BaseBluetoothGattCallback<XossDevice> {
        public SprintCallback(XossDevice xossDevice) {
            super(xossDevice);
        }

        @Override
        public void onCharacteristicRead(BluetoothGatt bluetoothGatt, BluetoothGattCharacteristic bluetoothGattCharacteristic, int i) {
            super.onCharacteristicRead(bluetoothGatt, bluetoothGattCharacteristic, i);

            Log.d("wangsm_bt", " XossDevice, onCharacteristicRead, Uuid:   " + bluetoothGattCharacteristic.getUuid());
            if (bluetoothGattCharacteristic.getUuid().equals(SpecificationAttributes.BLE_BATTERY_CHARACTERISTIC)) {
                int intValue = bluetoothGattCharacteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0);
                this.mClientRef.setBattery(intValue);
                DeviceCompat.notifyBattery(this.mClientRef.mAppContext, this.mClientRef, intValue);
            } else if (bluetoothGattCharacteristic.getUuid().equals(SpecificationAttributes.BLE_DEVICE_INFORMATION_FIRMWARE_CHARACTERISTIC)) {
                String stringValue = bluetoothGattCharacteristic.getStringValue(0);
                this.mClientRef.setFirmwareVersion(stringValue);
                DeviceCompat.notifyFirmwareVersion(this.mClientRef.mAppContext, this.mClientRef, stringValue);
            } else if (bluetoothGattCharacteristic.getUuid().equals(SpecificationAttributes.BLE_DEVICE_INFORMATION_MANUFACTURER_CHARACTERISTIC)) {
                this.mClientRef.setManufacturer(bluetoothGattCharacteristic.getStringValue(0));
            } else if (bluetoothGattCharacteristic.getUuid().equals(SpecificationAttributes.BLE_DEVICE_INFORMATION_MODEL_CHARACTERISTIC)) {
                Log.d("wangsm_bt", " the mode name is: " + bluetoothGattCharacteristic.getStringValue(0));
                this.mClientRef.setModel(bluetoothGattCharacteristic.getStringValue(0));
            } else if (bluetoothGattCharacteristic.getUuid().equals(SpecificationAttributes.BLE_DEVICE_INFORMATION_SERIAL_CHARACTERISTIC)) {
                Log.d("wangsm_bt", " the serial number is: " + bluetoothGattCharacteristic.getStringValue(0));
                this.mClientRef.setSerial(bluetoothGattCharacteristic.getStringValue(0));
            } else if (bluetoothGattCharacteristic.getUuid().equals(SpecificationAttributes.BLE_DEVICE_INFORMATION_HARDWARE_CHARACTERISTIC)) {
                this.mClientRef.setHardwareVersion(bluetoothGattCharacteristic.getStringValue(0));
            } else if (bluetoothGattCharacteristic.getUuid().equals(SpecificationAttributes.BLE_DEVICE_INFORMATION_SOFTWARE_CHARACTERISTIC)) {
                this.mClientRef.setSoftwareVersion(bluetoothGattCharacteristic.getStringValue(0));
            }
            CharacteristicValueHelper.notifyCharacteristicValue(this.mClientRef.mAppContext, this.mClientRef.getAddress(), bluetoothGattCharacteristic);
        }

        @Override
        public void onCharacteristicChanged(BluetoothGatt bluetoothGatt, BluetoothGattCharacteristic bluetoothGattCharacteristic) {
            super.onCharacteristicChanged(bluetoothGatt, bluetoothGattCharacteristic);
            UUID uuid = bluetoothGattCharacteristic.getUuid();
            Log.d("wangsm_bt", " XossDevice, onCharacteristicChanged, Uuid:   " + bluetoothGattCharacteristic.getUuid());
            byte[] value = bluetoothGattCharacteristic.getValue();
            if (uuid.equals(XossDevice.WINGS_CONTROL_POINT)) {
                Response createResponse = Commands.createResponse(value);
                this.mClientRef.mSprintControlPointQueue.addLast(createResponse);
                this.mClientRef.d("Response: " + createResponse);
                Log.d("wangsm_bt", " XossDevice, onCharacteristicChanged, WINGS_CONTROL_POINT:   ");
            } else if (!YModems.isYModemCmd(value) || (this.mClientRef.yModenOutputStream != null && this.mClientRef.yModenOutputStream.getBytesReceived() < this.mClientRef.yModenOutputStream.getTotalBytes())) {
                if (uuid.equals(XossDevice.WINGS_YMODEM_PACKAGE_SENDER)) {
                    Log.d("wangsm_bt", " XossDevice, onCharacteristicChanged, WINGS_YMODEM_PACKAGE_SENDER:   ");
                    this.mClientRef.d("Data: " + ByteUtils.printlnByteArrayToUnsignHexString(value));
                    if (this.mClientRef.yModenOutputStream != null) {
                        try {
                            this.mClientRef.yModenOutputStream.write(value, 0, value.length);
                        } catch (IOException e) {
                            this.mClientRef.e(e);
                        }
                    }
                }
            } else {
                Log.d("wangsm_bt", " XossDevice, onCharacteristicChanged, others :   ");
                byte b = value[0];
                this.mClientRef.mSprintTransmissionControlQueue.addLast(b);
                this.mClientRef.d("YModemCmd: " + Integer.toHexString(b));
            }
        }
    }
//add by wangsm test code
    static BluetoothGattCallback callback = new BluetoothGattCallback() {
    @Override
    public void onServicesDiscovered(BluetoothGatt gatt, int status) {
        super.onServicesDiscovered(gatt, status);
    }

    @Override
    public void onCharacteristicRead(@NonNull BluetoothGatt gatt, @NonNull BluetoothGattCharacteristic characteristic, @NonNull byte[] value, int status) {
        super.onCharacteristicRead(gatt, characteristic, value, status);
    }

    @Override
    public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
        super.onCharacteristicWrite(gatt, characteristic, status);
    }

    @Override
    public void onDescriptorRead(@NonNull BluetoothGatt gatt, @NonNull BluetoothGattDescriptor descriptor, int status, @NonNull byte[] value) {
        super.onDescriptorRead(gatt, descriptor, status, value);
    }

    @Override
    public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
        super.onDescriptorWrite(gatt, descriptor, status);
    }
};
    public  static void ConnectTest(){
        BluetoothGatt bluetoothGatt = null;
        BluetoothDevice bluetoothDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice("F3:39:FC:A1:23:A6");
/*        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            Log.d("wangsm_bt"," ConnectTest >m");
             //bluetoothDevice.connectGatt(BleManager.getInstance().getContext(), false, callback, TRANSPORT_LE);
            bluetoothDevice.connectGatt(BleManager.getInstance().getContext(), false, callback);
        } else {
            Log.d("wangsm_bt"," ConnectTest < m");
            bluetoothDevice.connectGatt(BleManager.getInstance().getContext(), false, callback);
        }*/

        bluetoothGatt = bluetoothDevice.connectGatt(BleManager.getInstance().getContext(), false, callback, BluetoothDevice.TRANSPORT_LE, BluetoothDevice.PHY_LE_2M_MASK, null);
        bluetoothGatt.setPreferredPhy(BluetoothDevice.PHY_LE_2M_MASK, BluetoothDevice.PHY_LE_2M_MASK, BluetoothDevice.PHY_OPTION_NO_PREFERRED);

        //bluetoothGatt = mDevice.connectGatt(mContext, false, mBluetoothGattCallback);
       //bluetoothGatt = mDevice.connectGatt(mContext, false, mBluetoothGattCallback, BluetoothDevice.TRANSPORT_BREDR);
        //bluetoothGatt = mDevice.connectGatt(mContext, false, mBluetoothGattCallback);
        //bluetoothGatt = mDevice.connectGatt(mContext, false, mBluetoothGattCallback, BluetoothDevice.TRANSPORT_LE, BluetoothDevice.PHY_LE_2M_MASK, null);
       // bluetoothGatt = mDevice.connectGatt(mContext, false, mBluetoothGattCallback, BluetoothDevice.TRANSPORT_LE);
        //bluetoothGatt = mDevice.connectGatt(mContext, false, mBluetoothGattCallback);
        //bluetoothGatt = mDevice.connectGatt(mContext, false, mBluetoothGattCallback);
       // bluetoothGatt = mDevice.connectGatt(mContext, false, mBluetoothGattCallback, BluetoothDevice.TRANSPORT_LE, BluetoothDevice.PHY_LE_2M_MASK, null);
       // bluetoothGatt.setPreferredPhy(BluetoothDevice.PHY_LE_2M_MASK, BluetoothDevice.PHY_LE_2M_MASK, BluetoothDevice.PHY_OPTION_NO_PREFERRED);
       // bluetoothGatt = mDevice.connectGatt(mContext, false, mBluetoothGattCallback, BluetoothDevice.TRANSPORT_LE);

    }


}
